package com.example.bigupload.service.impl;


import cn.hutool.core.lang.Assert;
import com.example.bigupload.config.MinioProperties;
import com.example.bigupload.domain.FileChunk;
import com.example.bigupload.mapper.FileChunkMapper;
import com.example.bigupload.service.MinioService;
import com.example.bigupload.utils.MinioUtil;
import io.minio.ComposeObjectArgs;
import io.minio.ComposeSource;
import io.minio.ObjectWriteResponse;
import io.minio.RemoveObjectsArgs;
import io.minio.errors.*;
import io.minio.messages.Bucket;
import io.minio.messages.DeleteError;
import io.minio.messages.DeleteObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;


import javax.annotation.Resource;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class MinioServiceImpl implements MinioService {

    @Resource
    private MinioUtil minioUtil;
    @Resource
    private MinioProperties minioProperties;
    @Resource
    private FileChunkMapper fileChunkMapper;

    @Override
    public boolean bucketExists(String bucketName) {
        return minioUtil.bucketExists(bucketName);
    }


    @Override
    public void makeBucket(String bucketName) {
        minioUtil.makeBucket(bucketName);
    }

    @Override
    public List<String> listBucketName() {
        return minioUtil.listBucketNames();
    }

    @Override
    public List<Bucket> listBuckets() {
        return minioUtil.listBuckets();
    }

    @Override
    public boolean removeBucket(String bucketName) {
        return minioUtil.removeBucket(bucketName);
    }


    @Override
    public List<String> listObjectNames(String bucketName) {
        return minioUtil.listObjectNames(bucketName);
    }


    @Override
    public String putObject(MultipartFile file, String bucketName,String fileType) {
        try {
            bucketName = StringUtils.isNotBlank(bucketName) ? bucketName : minioProperties.getBucketName();
            if (!this.bucketExists(bucketName)) {
                this.makeBucket(bucketName);
            }
            String fileName = file.getOriginalFilename();

            String objectName = UUID.randomUUID().toString().replaceAll("-", "")
                    + fileName.substring(fileName.lastIndexOf("."));
            minioUtil.putObject(bucketName, file, objectName,fileType);
            System.out.println( minioProperties.getEndpoint()+":"+minioProperties.getPort()+"/"+bucketName+"/"+objectName);
            return objectName;
        } catch (Exception e) {
            e.printStackTrace();

        }
        return null;
    }

    @Override
    public InputStream downloadObject(String bucketName, String objectName) {
        return minioUtil.getObject(bucketName,objectName);
    }

    @Override
    public boolean removeObject(String bucketName, String objectName) {
        return minioUtil.removeObject(bucketName, objectName);
    }

    @Override
    public boolean removeListObject(String bucketName, List<String> objectNameList) {
        return minioUtil.removeObject(bucketName,objectNameList);
    }

    @Override
    public String getObjectUrl(String bucketName,String objectName) {
        return minioUtil.getObjectUrl(bucketName, objectName);
    }

    /**
     *  合并文件
     * @param fileMd5:md5
     * @param objectName:保存到minio的文件名称
     * @return
     */
    @Override
    public ObjectWriteResponse mergeFiles(String fileMd5, String objectName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {

        //存放分片minio地址
        List<FileChunk> fileChunkParamByMd5 = fileChunkMapper.findFileChunkParamByMd5(fileMd5);
        Assert.isTrue(!CollectionUtils.isEmpty(fileChunkParamByMd5),"没有查询到指定的MD5分片信息");

        /**
         *  注意这里的,将所有的分片信息全部查询出来后，根据前端传递过来的分片序号进行
         *  从小到大排序，否者合并后的文件会损坏打不开
         */
        List<String> fileList =fileChunkParamByMd5.stream().sorted((u1,u2)->  Integer.compare(u1.getChunkNumber(),u2.getChunkNumber()))
                .map(auth->auth.getOssPath())
                .collect(Collectors.toList());

        //将获取需要合并的分片的oss路径组装成ComposeSource
        List<ComposeSource> sourceObjectList = new ArrayList<>(fileList.size());
        for (String chunk : fileList){
            sourceObjectList.add(
                    ComposeSource.builder()
                            .bucket("filetest")//桶名
                            .object(chunk)
                            .build()
            );
        }

        //合并分片
        ComposeObjectArgs composeObjectArgs = ComposeObjectArgs.builder()
                .bucket("filetest")//桶名
                //合并后的文件的objectname
                .object(objectName)//合并后的文件名
                //指定源文件
                .sources(sourceObjectList)
                .build();

        ObjectWriteResponse objectWriteResponse = minioUtil.composeObject(composeObjectArgs);
        return objectWriteResponse;
    }



}
